Welcome to the ATFS (Alliance for Tropical Research Science) data harmonization app!

1 Intro

The app is a tool meant to be used by 2 or more networks that are planing on combining their data for a common analysis.

1.1 Profiles

The app relies on “Profiles” that indicate how the data is stored in the file(s) provided: names of columns storing the DBH, the census ID, the tree tag, units of measurements etc…

A profile is a .rds file that is downloaded via the app once all the information about the data has been provided in the Headers and Units tab of the app.

One same profile can be uploaded as “input profile” in the Headers and Units tab, to speed up the process once your network’s data has been profiled, and/or as “output profile” in the Output format tab, to transform other networks’ data into that profile.

Some networks have their profile stored within the app.

1.2 Getting your data ready

The app only accepts CSV files.

It performs best if all the information that you want to share is collated into one analytical file, so we recommend that you append your species and plot information to your measurement information beforehand, and upload that one bigger file into the app.

That said, you can decide to utilize the app to do exactly that. There is no limit to the number of files you can upload but they all need to connect to each other in one way or another, so that by a stacking and/or merging them, it is possible to collate them down to one file. We will get to this in more detail in a moment.

The app also relies on tidy data, which means that every column is a variable, every row is an observation and every cell is a single value. For example, a data set with multiple column for the DBH measurement (e.g. DBH_2015, DBH_2020 etc…) is not a tidy data set. Instead, there should be a column for the variable year (which, in our example, will take a value of 2015 or 2020), and a column for DBH. If your data is not in a tidy format, the Tidy table tab will help you reshape your data.

1.3 R package

The app relies on functions that are maintained in a GitHub R package located here: https://github.com/Alliance-for-Tropical-Forest-Science/DataHarmonization.

1.4 Getting the app to start

1.4.1 Running the app on your local machine

We recommend to run the app on your local machine (via R and RStudio) if one of the following cases apply to you:

  • You have poor internet connection
  • You are working with large data files
  • You are familiar with the development of Shiny apps and would like to troubleshoot any issues you may encounter yourself

To open the app in R, you will need to install the DataHarmonization R package and launch Shiny with the following lines of code.

# install the R package

devtools::install_github("Alliance-for-Tropical-Forest-Science/DataHarmonization", build_vignettes = TRUE)
Downloading GitHub repo Alliance-for-Tropical-Forest-Science/DataHarmonization@HEAD

Note that you may need to install devtools package first and that installing the DataHarmonization R package may ask you to update a list packages.

You’ll want to re-install the package every once in a while, to get the latest version of the app.

1.4.2 Running the app online

If you don’t have R and RStudio and if your data is not too big, you can choose to run the online version of the app by clicking on this link. Note that online version may be lagging behind the GitHub version.

2 Interacting with the app

Once the app is launched you can start interacting with it.

There are multiple tabs to go through. Some tabs will be skipped automatically if they don’t apply to your situation and you may skip others if you don’t need/want them.

When you land on a tab, always advance with an action button (even if skipping) so your inputs are taken into account. You may use the navigation panel to return to a previous tab but remember to click on an action button to save your updated entries.

2.1 Upload your file(s)

This tab starts with information that we already covered in the intro. The checklist is only a guideline to help you getting ready, and you don’t actually need to check the boxes to move on.

The numbered tasks are the elements that you do need to complete to be able to move forward.

  1. Indicate how many tables you wish to upload

  2. Indicate the finest level of measurement in your data:

    • Plot: if your data only consists of plot level measurements like species richness, total basal area, total number of stems etc…
    • Species: if your data consists of species level measurements like abundance, basal area etc… This does not prevent you from also uploading plot level information that is stored in a separate file.
    • Tree: if your data consists of tree diameters, circumference,… and you are only measuring the main stem of each tree. This does not prevent you from also uploading plot and species level information if they are stored in separate file(s).
    • Stem: if your data consists of stem diameters, circumference,… and some stems belong to a same tree. This does not prevent you from uploading plot and species level information if they are stored in a separate file(s).

Again, even if you are uploading plot level information but have a stem level data, you should upload that file along and indicate that your level of measurement is “Stem”.

  1. Upload you tables. You’ll have as many upload boxes as you indicated needing in step 1. For each of them:

    • click on Browse... and navigate to the csv file you want to upload.
    • Type a more meaningful name to replace the generic “Table1”, “Table2” etc… This is particularly useful if you are uploading more than one file.
    • Check on the right hand side that the columns and rows of your data are rendering properly.
    • In the unlikely event that your tables are not rendering properly, adjust the parameters (separator and header) by clicking on the little gear icon .
  2. Click on SUBMIT to proceed to the next step.

2.2 Stack tables

If you uploaded more than one table, you will be prompted to the Stack tables tab, but this tab will be skipped if you only uploaded one table.

You will need to stack 2 or more tables if you are collecting the same information in multiple files. This can be the case if, for example, you are keeping your measurements from different plots in different files. Or you are keeping one file per census.

If you don’t need to stack tables, click on SKIP THIS STEP.

It is important that the files you are stacking have the same set of columns.

  1. Select all the tables that need to be stacked

  2. Click on STACK TABLES

  3. Double check your newly created table looks ok

  4. Click on GO TO MERGE to proceed to the next step. (Note: if you are down to one table at this stage the button’s label will change, so click SKIP MERGING SINCE ALL YOUR DATA IS NOW STACKED).

2.3 Merge tables

If you uploaded more than one table and not all of them were stacked, you will be prompted to the Merge tables tab, but this tab will be skipped if you only uploaded one table, or if all your tables were stacked.

At the end of this stage you have to be down to one table.

You need to use merging if, e.g., your species or your plot information is stored in a different table than your measurement table, and there is at least one “key” column that you can use to connect the tables together.

  1. In Merge this table, select the main measurement table (the one onto which you want to merge extra information into, from other tables). Note that this may be your now stacked table.

  2. In And this table, Select the table that you want to bring information from.

  3. Click on both blue arrows.

  4. In the two dropdown menus about the ‘KEY column(s)’, select the column(s) that allow to connect the to tables together.Select all columns that are common between tables, otherwise columns will be repeated in the output, with extension ‘.y’ in the name of the second table.

  5. click on ‘MERGE TABLES’.

  6. If you are still not down to one table, another box will appear. Repeat 1-5 with the remaining tables.

  7. click on ‘GO TO TIDY’.

2.4 Tidy table

At this stage, we want to make sure your data has one row per observation and one variable per column.

If you collected the same type of information in several columns (e.g. you added a column each time you visited a tree, or for each stem of the tree etc…), you need to “tidy” your table (also called wide-to-long reshaping).

  1. In the top-most box, use the radio-buttons to indicate the reason you added new columns for a new observation.

  2. The next set of boxes are pre-filled with our best guesses at the columns that may contain the same variable (columns that have similar names like dbh1, dbh2, or year1, year2…). Our guess may be terrible. Your role is to:

    1. Indicate the name of the new column that you wish your variable to be called (e.g. dbh) in the text box. Note that this should start by a letter and have no space.

    2. Select all the columns of your data that represent the variable indicated in step a. (e.g dbh1 and dbh2) using the drop-down menu.

    3. Tick the little tick-box on the upper-left corner of the box, to indicated that you do want to take into account what you selected.

  3. Repeat a-c for the next variable(s), e.g. you may need a box to indicate year in the text box and year1 and year2 in the drop-down menu. Don’t forget to tick the tick-box for those variables too.

  4. Click on ‘TIDY’

  5. Click on ‘GO TO HEADERS’

2.5 Headers and Units

Here, we want to know in what column some key information is stored.

  1. If…

    • A. … your data follows one of our pre-loaded standards: You can select it to help filing out some of the general information. But you should double check that accurately describe your particular data set.
    • B. … you have already gone through this step and saved your profile (.rds file): You can upload your profile. Double check that the information is filled out properly.
    • C. …This is your first time on this page: You have to go through all the drop-down menus:
      • column 1: Go through this column before indicating more information in column 2. For each element, select the name of the field of your data, if any, that corresponds the best to what is asked. Leave “none” if none of your variable apply.
      • column 2: Complete the information of that column after you are done with the information of column 1, because some field may appear/disappear depending on what you entered in 1.
      • Once you are done, save your profile (a .rds file) so you won’t need to go through all of this again (see B. above)
  2. click on ‘APPLY CHANGES’ and read any warnings that may popup, adjust your entries if possible (it is okay to ignore warnings) and re-apply your changes. Save (or update if needed) your profile (.rds file)

  3. Check your new formated data looks ok. The headers and units are now following ATFS’s standard. You can see what those are by clicking the little button.

  4. click on ‘NEXT’

2.6 Codes

You’ll be prompted to this tab if you indicated column(s) for ‘tree codes’ in the Tree Measurement section of the previous tab.

The table shows the list of codes that are available in the column(s) you indicated. If you intend to translate these codes to match the ones of another profile (which you will be able to do at a later step), or vice versa, you need to fill this table out.

Once you are done with the table you can update your profile (by downloading and overwriting your .rds file), so it will be faster next time. If you have already saved your profile after this step, and used it to fill out the previous step, you can click on the “Use your profile” button to automatically fill the table.

There is a list of predefined definitions, which, if used by you and your collaborator, will help automatically translate your codes. But if you can’t find a definition that matches yours, just type your own.

2.7 Corrections

Corrections may be applied to botanical names, life status and/or diameters.

If you are planing on using corrections, we recommend that you coordinate with your collaborator(s), because it may make more sense to first skip them and apply them in a new app session in which the collated data set is uploaded, to ensure uniformity of corrections across data sets.

If you select “Yes” to any of the corrections, you will be able to change the default parameters. We recommend to keep most parameters to their default values.

The functions will add new columns to your data (indicated with _DataHarmonizationCor suffix) and won’t alter your original columns.

Note that some of these function are quite slow and it can take a few minutes for the output to show up.

You can visualize the correction applied in the tabs below the correction boxes.

2.8 Output format

2.8.1 Selecting an output format

This is where the magic happens.

Select or uploaded an output profile (.rds file) and click on Apply Profile. This will transform your data’s units and column names into the output profile’s headers and units. If you and your collaborator have a code table, you will be prompted to the code translation table. If not, you can check that the output data looks good and move on to ‘the download tab’.

Note: When you upload a profile, there is a chance that it is “obsolete” if the profile was created on an earlier version of the app. If that is the case, you’ll be notified by a pop up window and the items missing in the profile will be listed. To be able to use that profile, you will need an updated version of it (see How to update a profile in the Troubleshooting section below.)

2.8.2 Translating code

This section of the tab will only appear if you had to fill in the code table in the Codes tab and the output profile you selected or uploaded also has a code table. You can now look through both sets of codes and indicate the ones that are equivalent by checking the corresponding radio button(s).

If you hover over the column names, you will see the definitions of the output profile.

Click on “See definition” to double check that the mapping of codes is what you intended.

When you are happy, apply the mapping and you will see columns added to your table. They will have the column names that the output profile expects and will be filled with the output codes, based on the codes in your column(s) and the mapping you indicated.

2.9 Download the output data and metadata

Clicking on “save all” generates a zip file with all the files you should need. If you have tree codes and applied a tree code mapping, the zip will include a CSV file with the translation table (which you can upload in the code translation step to speed up the process next time.)

2.10 Help

This a simplified version of this tutorial.

3 Troubleshooting

3.1 How to update a profile

If your output profile (.rds file) is obsolete there are two options, which should be done by the person who created the profile in the first place:

  • For R savvy people: open the .rds file in R. It is a list. Add the missing element(s) that were listed in the pop up window that said that the profile was obsolete by giving them the value that applies to the output profile. For example, if “Cluster” was missing you can do:

      profile <- readRDS("[YOUR PATH]/[YOUR PROFILENAME].rds")
      profile$Cluster <- "none"
      saveRDS(profile, "[YOUR PATH]/[YOUR PROFILENAME].rds")
  • For non-R savvy people: go through the app again. It should go fast as you will be able to upload your obsolete profile as an input. Make sure to save and overwrite your profile. If the elements missing did not apply to you, they will now exist with value “none” in your profile.

LS0tCnRpdGxlOiAiRGF0YSBIYXJtb25pemF0aW9uIEFwcCBUdXRvcmlhbCIKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJVktJW0tJWQnKWAiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIGRmX3ByaW50OiBwYWdlZAogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCi0tLQoKYGBge3IgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShmb250YXdlc29tZSkKYGBgIAoKCgoKV2VsY29tZSB0byB0aGUgQVRGUyAoQWxsaWFuY2UgZm9yIFRyb3BpY2FsIFJlc2VhcmNoIFNjaWVuY2UpIGRhdGEgaGFybW9uaXphdGlvbiBhcHAhCgoKIyBJbnRybyB7I2ludHJvfQoKVGhlIGFwcCBpcyBhIHRvb2wgbWVhbnQgdG8gYmUgdXNlZCBieSAyIG9yIG1vcmUgbmV0d29ya3MgdGhhdCBhcmUgcGxhbmluZyBvbiBjb21iaW5pbmcgdGhlaXIgZGF0YSBmb3IgYSBjb21tb24gYW5hbHlzaXMuCgojIyBQcm9maWxlcyB7I3Byb2ZpbGV9CgpUaGUgYXBwIHJlbGllcyBvbiAiUHJvZmlsZXMiIHRoYXQgaW5kaWNhdGUgaG93IHRoZSBkYXRhIGlzIHN0b3JlZCBpbiB0aGUgZmlsZShzKSBwcm92aWRlZDogbmFtZXMgb2YgY29sdW1ucyBzdG9yaW5nIHRoZSBEQkgsIHRoZSBjZW5zdXMgSUQsIHRoZSB0cmVlIHRhZywgdW5pdHMgb2YgbWVhc3VyZW1lbnRzIGV0Yy4uLgoKQSBwcm9maWxlIGlzIGEgLnJkcyBmaWxlIHRoYXQgaXMgZG93bmxvYWRlZCB2aWEgdGhlIGFwcCBvbmNlIGFsbCB0aGUgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGRhdGEgaGFzIGJlZW4gcHJvdmlkZWQgaW4gdGhlIFtgSGVhZGVycyBhbmQgVW5pdHNgXSgjSGVhZGVycykgdGFiIG9mIHRoZSBhcHAuCgpPbmUgc2FtZSBwcm9maWxlIGNhbiBiZSB1cGxvYWRlZCBhcyAiaW5wdXQgcHJvZmlsZSIgaW4gdGhlIFtgSGVhZGVycyBhbmQgVW5pdHNgXSgjSGVhZGVycykgdGFiLCB0byBzcGVlZCB1cCB0aGUgcHJvY2VzcyBvbmNlIHlvdXIgbmV0d29yaydzIGRhdGEgaGFzIGJlZW4gcHJvZmlsZWQsIGFuZC9vciBhcyAib3V0cHV0IHByb2ZpbGUiIGluIHRoZSBbYE91dHB1dCBmb3JtYXRgXSgjT3V0cHV0Rm9ybWF0KSB0YWIsIHRvIHRyYW5zZm9ybSBvdGhlciBuZXR3b3JrcycgZGF0YSBpbnRvIHRoYXQgcHJvZmlsZS4KClNvbWUgbmV0d29ya3MgaGF2ZSB0aGVpciBwcm9maWxlIHN0b3JlZCB3aXRoaW4gdGhlIGFwcC4KCiMjIEdldHRpbmcgeW91ciBkYXRhIHJlYWR5IHsjcHJlcGRhdGF9CgpUaGUgYXBwIG9ubHkgYWNjZXB0cyBDU1YgZmlsZXMuIAoKSXQgcGVyZm9ybXMgYmVzdCBpZiBhbGwgdGhlIGluZm9ybWF0aW9uIHRoYXQgeW91IHdhbnQgdG8gc2hhcmUgaXMgY29sbGF0ZWQgaW50byBvbmUgYW5hbHl0aWNhbCBmaWxlLCBzbyB3ZSByZWNvbW1lbmQgdGhhdCB5b3UgYXBwZW5kIHlvdXIgc3BlY2llcyBhbmQgcGxvdCBpbmZvcm1hdGlvbiB0byB5b3VyIG1lYXN1cmVtZW50IGluZm9ybWF0aW9uIGJlZm9yZWhhbmQsIGFuZCB1cGxvYWQgdGhhdCBvbmUgYmlnZ2VyIGZpbGUgaW50byB0aGUgYXBwLgoKVGhhdCBzYWlkLCB5b3UgY2FuIGRlY2lkZSB0byB1dGlsaXplIHRoZSBhcHAgdG8gZG8gZXhhY3RseSB0aGF0LiBUaGVyZSBpcyBubyBsaW1pdCB0byB0aGUgbnVtYmVyIG9mIGZpbGVzIHlvdSBjYW4gdXBsb2FkIGJ1dCB0aGV5IGFsbCBuZWVkIHRvIGNvbm5lY3QgdG8gZWFjaCBvdGhlciBpbiBvbmUgd2F5IG9yIGFub3RoZXIsIHNvIHRoYXQgYnkgYSBzdGFja2luZyBhbmQvb3IgbWVyZ2luZyB0aGVtLCBpdCBpcyBwb3NzaWJsZSB0byBjb2xsYXRlIHRoZW0gZG93biB0byBvbmUgZmlsZS4gV2Ugd2lsbCBnZXQgdG8gdGhpcyBpbiBtb3JlIGRldGFpbCBpbiBhIG1vbWVudC4KClRoZSBhcHAgYWxzbyByZWxpZXMgb24gW3RpZHldKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy90aWR5ci92aWduZXR0ZXMvdGlkeS1kYXRhLmh0bWwjOn46dGV4dD1UaWR5JTIwZGF0YSUyMGlzJTIwYSUyMHN0YW5kYXJkLEV2ZXJ5JTIwY29sdW1uJTIwaXMlMjBhJTIwdmFyaWFibGUuKSBkYXRhLCB3aGljaCBtZWFucyB0aGF0IGV2ZXJ5IGNvbHVtbiBpcyBhIHZhcmlhYmxlLCBldmVyeSByb3cgaXMgYW4gb2JzZXJ2YXRpb24gYW5kIGV2ZXJ5IGNlbGwgaXMgYSBzaW5nbGUgdmFsdWUuIEZvciBleGFtcGxlLCBhIGRhdGEgc2V0IHdpdGggbXVsdGlwbGUgY29sdW1uIGZvciB0aGUgREJIIG1lYXN1cmVtZW50IChlLmcuIERCSF8yMDE1LCBEQkhfMjAyMCBldGMuLi4pIGlzIG5vdCBhIHRpZHkgZGF0YSBzZXQuIEluc3RlYWQsIHRoZXJlIHNob3VsZCBiZSBhIGNvbHVtbiBmb3IgdGhlIHZhcmlhYmxlIGB5ZWFyYCAod2hpY2gsIGluIG91ciBleGFtcGxlLCB3aWxsIHRha2UgYSB2YWx1ZSBvZiAyMDE1IG9yIDIwMjApLCBhbmQgYSBjb2x1bW4gZm9yIGBEQkhgLgpJZiB5b3VyIGRhdGEgaXMgbm90IGluIGEgdGlkeSBmb3JtYXQsIHRoZSBbYFRpZHkgdGFibGVgXSgjVGlkeWluZykgdGFiIHdpbGwgaGVscCB5b3UgcmVzaGFwZSB5b3VyIGRhdGEuIAoKCiMjIFIgcGFja2FnZSB7I3BhY2thZ2V9CgpUaGUgYXBwIHJlbGllcyBvbiBmdW5jdGlvbnMgdGhhdCBhcmUgbWFpbnRhaW5lZCBpbiBhIEdpdEh1YiBSIHBhY2thZ2UgbG9jYXRlZCBoZXJlOiBodHRwczovL2dpdGh1Yi5jb20vQWxsaWFuY2UtZm9yLVRyb3BpY2FsLUZvcmVzdC1TY2llbmNlL0RhdGFIYXJtb25pemF0aW9uLgoKIyMgR2V0dGluZyB0aGUgYXBwIHRvIHN0YXJ0IHsjc3RhcnR9CgojIyMgUnVubmluZyB0aGUgYXBwIG9uIHlvdXIgbG9jYWwgbWFjaGluZSB7I2xvY2FsUnVufQoKV2UgcmVjb21tZW5kIHRvIHJ1biB0aGUgYXBwIG9uIHlvdXIgbG9jYWwgbWFjaGluZSAodmlhIFIgYW5kIFJTdHVkaW8pIGlmIG9uZSBvZiB0aGUgZm9sbG93aW5nIGNhc2VzIGFwcGx5IHRvIHlvdToKCiAtIFlvdSBoYXZlIHBvb3IgaW50ZXJuZXQgY29ubmVjdGlvbgogLSBZb3UgYXJlIHdvcmtpbmcgd2l0aCBsYXJnZSBkYXRhIGZpbGVzCiAtIFlvdSBhcmUgZmFtaWxpYXIgd2l0aCB0aGUgZGV2ZWxvcG1lbnQgb2YgU2hpbnkgYXBwcyBhbmQgd291bGQgbGlrZSB0byB0cm91Ymxlc2hvb3QgYW55IGlzc3VlcyB5b3UgbWF5IGVuY291bnRlciB5b3Vyc2VsZgogClRvIG9wZW4gdGhlIGFwcCBpbiBSLCB5b3Ugd2lsbCBuZWVkIHRvIGluc3RhbGwgdGhlIERhdGFIYXJtb25pemF0aW9uIFIgcGFja2FnZSBhbmQgbGF1bmNoIFNoaW55IHdpdGggdGhlIGZvbGxvd2luZyBsaW5lcyBvZiBjb2RlLgoKYGBge3J9CiMgaW5zdGFsbCB0aGUgUiBwYWNrYWdlCgpkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoIkFsbGlhbmNlLWZvci1Ucm9waWNhbC1Gb3Jlc3QtU2NpZW5jZS9EYXRhSGFybW9uaXphdGlvbiIsIGJ1aWxkX3ZpZ25ldHRlcyA9IFRSVUUpCgojIHJ1biB0aGUgYXBwCgpzaGlueTo6cnVuR2l0SHViKCAiQWxsaWFuY2UtZm9yLVRyb3BpY2FsLUZvcmVzdC1TY2llbmNlL0RhdGFIYXJtb25pemF0aW9uIiwgc3ViZGlyID0gImluc3QvYXBwIikKYGBgCgpOb3RlIHRoYXQgeW91IG1heSBuZWVkIHRvIGluc3RhbGwgYGRldnRvb2xzYCBwYWNrYWdlIGZpcnN0IGFuZCB0aGF0IGluc3RhbGxpbmcgdGhlIERhdGFIYXJtb25pemF0aW9uIFIgcGFja2FnZSBtYXkgYXNrIHlvdSB0byB1cGRhdGUgYSBsaXN0IHBhY2thZ2VzLgoKKipZb3UnbGwgd2FudCB0byByZS1pbnN0YWxsIHRoZSBwYWNrYWdlIGV2ZXJ5IG9uY2UgaW4gYSB3aGlsZSwgdG8gZ2V0IHRoZSBsYXRlc3QgdmVyc2lvbiBvZiB0aGUgYXBwLioqCgojIyMgUnVubmluZyB0aGUgYXBwIG9ubGluZSB7I29ubGluZVJ1bn0KCklmIHlvdSBkb24ndCBoYXZlIFIgYW5kIFJTdHVkaW8gYW5kIGlmIHlvdXIgZGF0YSBpcyBub3QgdG9vIGJpZywgeW91IGNhbiBjaG9vc2UgdG8gcnVuIHRoZSBvbmxpbmUgdmVyc2lvbiBvZiB0aGUgYXBwIGJ5IGNsaWNraW5nIG9uIHRoaXMgW2xpbmtdKGh0dHBzOi8vdmFsZW50aW5laGVyci5zaGlueWFwcHMuaW8vVG1GT19BY2NlbE5ldC8pLiAKTm90ZSB0aGF0IG9ubGluZSB2ZXJzaW9uIG1heSBiZSBsYWdnaW5nIGJlaGluZCB0aGUgR2l0SHViIHZlcnNpb24uIAoKCiMgSW50ZXJhY3Rpbmcgd2l0aCB0aGUgYXBwIHsjaW50ZXJhY3R9CgpPbmNlIHRoZSBhcHAgaXMgbGF1bmNoZWQgeW91IGNhbiBzdGFydCBpbnRlcmFjdGluZyB3aXRoIGl0LgoKVGhlcmUgYXJlIG11bHRpcGxlIHRhYnMgdG8gZ28gdGhyb3VnaC4gClNvbWUgdGFicyB3aWxsIGJlIHNraXBwZWQgYXV0b21hdGljYWxseSBpZiB0aGV5IGRvbid0IGFwcGx5IHRvIHlvdXIgc2l0dWF0aW9uIGFuZCB5b3UgbWF5IHNraXAgb3RoZXJzIGlmIHlvdSBkb24ndCBuZWVkL3dhbnQgdGhlbS4KCldoZW4geW91IGxhbmQgb24gYSB0YWIsICoqYWx3YXlzIGFkdmFuY2Ugd2l0aCBhbiBhY3Rpb24gYnV0dG9uIChldmVuIGlmIHNraXBwaW5nKSBzbyB5b3VyIGlucHV0cyBhcmUgdGFrZW4gaW50byBhY2NvdW50KiouIFlvdSBtYXkgdXNlIHRoZSBuYXZpZ2F0aW9uIHBhbmVsIHRvIHJldHVybiB0byBhIHByZXZpb3VzIHRhYiBidXQgcmVtZW1iZXIgdG8gY2xpY2sgb24gYW4gYWN0aW9uIGJ1dHRvbiB0byBzYXZlIHlvdXIgdXBkYXRlZCBlbnRyaWVzLgoKCgojIyBVcGxvYWQgeW91ciBmaWxlKHMpIHsjdXBsb2FkfQoKVGhpcyB0YWIgc3RhcnRzIHdpdGggaW5mb3JtYXRpb24gdGhhdCB3ZSBhbHJlYWR5IGNvdmVyZWQgaW4gdGhlIFtpbnRyb10oI2ludHJvKS4gVGhlIGNoZWNrbGlzdCBpcyBvbmx5IGEgZ3VpZGVsaW5lIHRvIGhlbHAgeW91IGdldHRpbmcgcmVhZHksIGFuZCB5b3UgZG9uJ3QgYWN0dWFsbHkgbmVlZCB0byBjaGVjayB0aGUgYm94ZXMgdG8gbW92ZSBvbi4KClRoZSBudW1iZXJlZCB0YXNrcyBhcmUgdGhlIGVsZW1lbnRzIHRoYXQgeW91IGRvIG5lZWQgdG8gY29tcGxldGUgdG8gYmUgYWJsZSB0byBtb3ZlIGZvcndhcmQuCgogMS4gSW5kaWNhdGUgaG93IG1hbnkgdGFibGVzIHlvdSB3aXNoIHRvIHVwbG9hZAogMi4gSW5kaWNhdGUgdGhlIGZpbmVzdCBsZXZlbCBvZiBtZWFzdXJlbWVudCBpbiB5b3VyIGRhdGE6CiAKICAgIC0gKipQbG90Kio6IGlmIHlvdXIgZGF0YSBvbmx5IGNvbnNpc3RzIG9mIHBsb3QgbGV2ZWwgbWVhc3VyZW1lbnRzIGxpa2Ugc3BlY2llcyByaWNobmVzcywgdG90YWwgYmFzYWwgYXJlYSwgdG90YWwgbnVtYmVyIG9mIHN0ZW1zIGV0Yy4uLgogICAgLSAqKlNwZWNpZXMqKjogaWYgeW91ciBkYXRhIGNvbnNpc3RzIG9mIHNwZWNpZXMgbGV2ZWwgbWVhc3VyZW1lbnRzIGxpa2UgYWJ1bmRhbmNlLCBiYXNhbCBhcmVhIGV0Yy4uLiBUaGlzIGRvZXMgbm90IHByZXZlbnQgeW91IGZyb20gYWxzbyB1cGxvYWRpbmcgcGxvdCBsZXZlbCBpbmZvcm1hdGlvbiB0aGF0IGlzIHN0b3JlZCBpbiBhIHNlcGFyYXRlIGZpbGUuCiAgICAtICoqVHJlZSoqOiBpZiB5b3VyIGRhdGEgY29uc2lzdHMgb2YgdHJlZSBkaWFtZXRlcnMsIGNpcmN1bWZlcmVuY2UsLi4uIGFuZCB5b3UgYXJlIG9ubHkgbWVhc3VyaW5nIHRoZSBtYWluIHN0ZW0gb2YgZWFjaCB0cmVlLiBUaGlzIGRvZXMgbm90IHByZXZlbnQgeW91IGZyb20gYWxzbyB1cGxvYWRpbmcgcGxvdCBhbmQgc3BlY2llcyBsZXZlbCBpbmZvcm1hdGlvbiBpZiB0aGV5IGFyZSBzdG9yZWQgaW4gc2VwYXJhdGUgZmlsZShzKS4KICAgIC0gKipTdGVtKio6IGlmIHlvdXIgZGF0YSBjb25zaXN0cyBvZiBzdGVtIGRpYW1ldGVycywgY2lyY3VtZmVyZW5jZSwuLi4gYW5kIHNvbWUgc3RlbXMgYmVsb25nIHRvIGEgc2FtZSB0cmVlLiBUaGlzIGRvZXMgbm90IHByZXZlbnQgeW91IGZyb20gdXBsb2FkaW5nIHBsb3QgYW5kIHNwZWNpZXMgbGV2ZWwgaW5mb3JtYXRpb24gaWYgdGhleSBhcmUgc3RvcmVkIGluIGEgc2VwYXJhdGUgZmlsZShzKS4KIApBZ2FpbiwgZXZlbiBpZiB5b3UgYXJlIHVwbG9hZGluZyBwbG90IGxldmVsIGluZm9ybWF0aW9uIGJ1dCBoYXZlIGEgc3RlbSBsZXZlbCBkYXRhLCB5b3Ugc2hvdWxkIHVwbG9hZCB0aGF0IGZpbGUgYWxvbmcgYW5kIGluZGljYXRlIHRoYXQgeW91ciBsZXZlbCBvZiBtZWFzdXJlbWVudCBpcyAiU3RlbSIuCgogMy4gVXBsb2FkIHlvdSB0YWJsZXMuIFlvdSdsbCBoYXZlIGFzIG1hbnkgdXBsb2FkIGJveGVzIGFzIHlvdSBpbmRpY2F0ZWQgbmVlZGluZyBpbiBzdGVwIDEuIEZvciBlYWNoIG9mIHRoZW06CiAKICAgIC0gY2xpY2sgb24gYEJyb3dzZS4uLmAgYW5kIG5hdmlnYXRlIHRvIHRoZSBjc3YgZmlsZSB5b3Ugd2FudCB0byB1cGxvYWQuCiAgICAtIFR5cGUgYSBtb3JlIG1lYW5pbmdmdWwgbmFtZSB0byByZXBsYWNlIHRoZSBnZW5lcmljICJUYWJsZTEiLCAiVGFibGUyIiBldGMuLi4gVGhpcyBpcyBwYXJ0aWN1bGFybHkgdXNlZnVsIGlmIHlvdSBhcmUgdXBsb2FkaW5nIG1vcmUgdGhhbiBvbmUgZmlsZS4KICAgIC0gQ2hlY2sgb24gdGhlIHJpZ2h0IGhhbmQgc2lkZSB0aGF0IHRoZSBjb2x1bW5zIGFuZCByb3dzIG9mIHlvdXIgZGF0YSBhcmUgcmVuZGVyaW5nIHByb3Blcmx5LiAKICAgIC0gSW4gdGhlIHVubGlrZWx5IGV2ZW50IHRoYXQgeW91ciB0YWJsZXMgYXJlIG5vdCByZW5kZXJpbmcgcHJvcGVybHksIGFkanVzdCB0aGUgcGFyYW1ldGVycyAoc2VwYXJhdG9yIGFuZCBoZWFkZXIpIGJ5IGNsaWNraW5nIG9uIHRoZSBsaXR0bGUgZ2VhciBpY29uIGByIGZhKG5hbWUgPSAiY29nIilgLgoKIDQuICoqQ2xpY2sgb24gU1VCTUlUKiogdG8gcHJvY2VlZCB0byB0aGUgbmV4dCBzdGVwLgogCiAgICAgCiFbXShVcGxvYWQuZ2lmKQoKCiMjIFN0YWNrIHRhYmxlcyB7I1N0YWNraW5nfQoKSWYgeW91IHVwbG9hZGVkIG1vcmUgdGhhbiBvbmUgdGFibGUsIHlvdSB3aWxsIGJlIHByb21wdGVkIHRvIHRoZSBgU3RhY2sgdGFibGVzYCB0YWIsIGJ1dCB0aGlzIHRhYiB3aWxsIGJlIHNraXBwZWQgaWYgeW91IG9ubHkgdXBsb2FkZWQgb25lIHRhYmxlLgoKWW91IHdpbGwgbmVlZCB0byBzdGFjayAyIG9yIG1vcmUgdGFibGVzIGlmIHlvdSBhcmUgY29sbGVjdGluZyB0aGUgc2FtZSBpbmZvcm1hdGlvbiBpbiBtdWx0aXBsZSBmaWxlcy4gVGhpcyBjYW4gYmUgdGhlIGNhc2UgaWYsIGZvciBleGFtcGxlLCB5b3UgYXJlIGtlZXBpbmcgeW91ciBtZWFzdXJlbWVudHMgZnJvbSBkaWZmZXJlbnQgcGxvdHMgaW4gZGlmZmVyZW50IGZpbGVzLiBPciB5b3UgYXJlIGtlZXBpbmcgb25lIGZpbGUgcGVyIGNlbnN1cy4KCklmIHlvdSBkb24ndCBuZWVkIHRvIHN0YWNrIHRhYmxlcywgKipjbGljayBvbiBTS0lQIFRISVMgU1RFUCoqLgoKKipJdCBpcyBpbXBvcnRhbnQgdGhhdCB0aGUgZmlsZXMgeW91IGFyZSBzdGFja2luZyBoYXZlIHRoZSBzYW1lIHNldCBvZiBjb2x1bW5zLioqIAoKIDEuIFNlbGVjdCBhbGwgdGhlIHRhYmxlcyB0aGF0IG5lZWQgdG8gYmUgc3RhY2tlZAogCiAyLiAqKkNsaWNrIG9uIFNUQUNLIFRBQkxFUyoqCiAKIDMuIERvdWJsZSBjaGVjayB5b3VyIG5ld2x5IGNyZWF0ZWQgdGFibGUgbG9va3Mgb2sKIAogNC4gKipDbGljayBvbiBHTyBUTyBNRVJHRSoqIHRvIHByb2NlZWQgdG8gdGhlIG5leHQgc3RlcC4gKE5vdGU6IGlmIHlvdSBhcmUgZG93biB0byBvbmUgdGFibGUgYXQgdGhpcyBzdGFnZSB0aGUgYnV0dG9uJ3MgbGFiZWwgd2lsbCBjaGFuZ2UsIHNvICoqY2xpY2sgU0tJUCBNRVJHSU5HIFNJTkNFIEFMTCBZT1VSIERBVEEgSVMgTk9XIFNUQUNLRUQqKikuCgoKCiFbXShTdGFjay5naWYpCgojIyBNZXJnZSB0YWJsZXMgeyNNZXJnaW5nfQoKSWYgeW91IHVwbG9hZGVkIG1vcmUgdGhhbiBvbmUgdGFibGUgYW5kIG5vdCBhbGwgb2YgdGhlbSB3ZXJlIHN0YWNrZWQsIHlvdSB3aWxsIGJlIHByb21wdGVkIHRvIHRoZSBgTWVyZ2UgdGFibGVzYCB0YWIsIGJ1dCB0aGlzIHRhYiB3aWxsIGJlIHNraXBwZWQgaWYgeW91IG9ubHkgdXBsb2FkZWQgb25lIHRhYmxlLCBvciBpZiBhbGwgeW91ciB0YWJsZXMgd2VyZSBzdGFja2VkLgoKQXQgdGhlIGVuZCBvZiB0aGlzIHN0YWdlIHlvdSBoYXZlIHRvIGJlIGRvd24gdG8gb25lIHRhYmxlLgoKWW91IG5lZWQgdG8gdXNlIG1lcmdpbmcgaWYsIGUuZy4sIHlvdXIgc3BlY2llcyBvciB5b3VyIHBsb3QgaW5mb3JtYXRpb24gaXMgc3RvcmVkIGluIGEgZGlmZmVyZW50IHRhYmxlIHRoYW4geW91ciBtZWFzdXJlbWVudCB0YWJsZSwgYW5kIHRoZXJlIGlzIGF0IGxlYXN0IG9uZSAia2V5IiBjb2x1bW4gdGhhdCB5b3UgY2FuIHVzZSB0byBjb25uZWN0IHRoZSB0YWJsZXMgdG9nZXRoZXIuCgoKIAogMS4gSW4gKipNZXJnZSB0aGlzIHRhYmxlKiosIHNlbGVjdCB0aGUgbWFpbiBtZWFzdXJlbWVudCB0YWJsZSAodGhlIG9uZSBvbnRvIHdoaWNoIHlvdSB3YW50IHRvIG1lcmdlIGV4dHJhIGluZm9ybWF0aW9uIGludG8sIGZyb20gb3RoZXIgdGFibGVzKS4gTm90ZSB0aGF0IHRoaXMgbWF5IGJlIHlvdXIgbm93IHN0YWNrZWQgdGFibGUuCiAKIDIuIEluICoqQW5kIHRoaXMgdGFibGUqKiwgU2VsZWN0IHRoZSB0YWJsZSB0aGF0IHlvdSB3YW50IHRvIGJyaW5nIGluZm9ybWF0aW9uIGZyb20uCiAKIDMuIDxzcGFuIHN0eWxlPSJjb2xvcjojMDBjMGVmOyI+Q2xpY2sgb24gYm90aCBibHVlIGFycm93cy48L3NwYW4+CiAKIDQuIEluIHRoZSB0d28gZHJvcGRvd24gbWVudXMgYWJvdXQgdGhlICdLRVkgY29sdW1uKHMpJywgc2VsZWN0IHRoZSBjb2x1bW4ocykgdGhhdCBhbGxvdyB0byBjb25uZWN0IHRoZSB0byB0YWJsZXMgdG9nZXRoZXIuKipTZWxlY3QgYWxsIGNvbHVtbnMgdGhhdCBhcmUgY29tbW9uIGJldHdlZW4gdGFibGVzLCBvdGhlcndpc2UgY29sdW1ucyB3aWxsIGJlIHJlcGVhdGVkIGluIHRoZSBvdXRwdXQsIHdpdGggZXh0ZW5zaW9uICcueScgaW4gdGhlIG5hbWUgb2YgdGhlIHNlY29uZCB0YWJsZS4qKgogCiA1LiAqKmNsaWNrIG9uICdNRVJHRSBUQUJMRVMnLioqCiAKIDYuIElmIHlvdSBhcmUgc3RpbGwgbm90IGRvd24gdG8gb25lIHRhYmxlLCBhbm90aGVyIGJveCB3aWxsIGFwcGVhci4gUmVwZWF0IDEtNSB3aXRoIHRoZSByZW1haW5pbmcgdGFibGVzLgogCiA3LiAqKmNsaWNrIG9uICdHTyBUTyBUSURZJy4qKgogCgohW10oTWVyZ2UuZ2lmKQoKIyMgVGlkeSB0YWJsZSB7I1RpZHlpbmd9CgoKQXQgdGhpcyBzdGFnZSwgd2Ugd2FudCB0byBtYWtlIHN1cmUgeW91ciBkYXRhIGhhcyAqKm9uZSByb3cgcGVyIG9ic2VydmF0aW9uIGFuZCBvbmUgdmFyaWFibGUgcGVyIGNvbHVtbi4qKgoKSWYgeW91IGNvbGxlY3RlZCB0aGUgc2FtZSB0eXBlIG9mIGluZm9ybWF0aW9uIGluIHNldmVyYWwgY29sdW1ucyAoZS5nLiB5b3UgYWRkZWQgYSBjb2x1bW4gZWFjaCB0aW1lIHlvdSB2aXNpdGVkIGEgdHJlZSwgb3IgZm9yIGVhY2ggc3RlbSBvZiB0aGUgdHJlZSBldGMuLi4pLCB5b3UgbmVlZCB0byAidGlkeSIgeW91ciB0YWJsZSAoYWxzbyBjYWxsZWQgd2lkZS10by1sb25nIHJlc2hhcGluZykuIAoKIDEuIEluIHRoZSB0b3AtbW9zdCBib3gsIHVzZSB0aGUgcmFkaW8tYnV0dG9ucyB0byBpbmRpY2F0ZSB0aGUgcmVhc29uIHlvdSBhZGRlZCBuZXcgY29sdW1ucyBmb3IgYSBuZXcgb2JzZXJ2YXRpb24uCiAKIDIuIFRoZSBuZXh0IHNldCBvZiBib3hlcyBhcmUgcHJlLWZpbGxlZCB3aXRoIG91ciBiZXN0IGd1ZXNzZXMgYXQgdGhlIGNvbHVtbnMgdGhhdCBtYXkgY29udGFpbiB0aGUgc2FtZSB2YXJpYWJsZSAoY29sdW1ucyB0aGF0IGhhdmUgc2ltaWxhciBuYW1lcyBsaWtlIGBkYmgxYCwgYGRiaDJgLCBvciAgYHllYXIxYCwgYHllYXIyYC4uLikuIE91ciBndWVzcyBtYXkgYmUgdGVycmlibGUuIFlvdXIgcm9sZSBpcyB0bzoKIAogICAgICBhLiBJbmRpY2F0ZSB0aGUgbmFtZSBvZiB0aGUgbmV3IGNvbHVtbiB0aGF0IHlvdSB3aXNoIHlvdXIgdmFyaWFibGUgdG8gYmUgY2FsbGVkIChlLmcuIGBkYmhgKSBpbiB0aGUgdGV4dCBib3guIE5vdGUgdGhhdCB0aGlzIHNob3VsZCBzdGFydCBieSBhIGxldHRlciBhbmQgaGF2ZSBubyBzcGFjZS4KICAgICAgIAogICAgICBiLiBTZWxlY3QgYWxsIHRoZSBjb2x1bW5zIG9mIHlvdXIgZGF0YSB0aGF0IHJlcHJlc2VudCB0aGUgdmFyaWFibGUgaW5kaWNhdGVkIGluIHN0ZXAgYS4gKGUuZyBgZGJoMWAgYW5kIGBkYmgyYCkgdXNpbmcgdGhlIGRyb3AtZG93biBtZW51LgoKICAgICAgYy4gVGljayB0aGUgbGl0dGxlIHRpY2stYm94IG9uIHRoZSB1cHBlci1sZWZ0IGNvcm5lciBvZiB0aGUgYm94LCB0byBpbmRpY2F0ZWQgdGhhdCB5b3UgZG8gd2FudCB0byB0YWtlIGludG8gYWNjb3VudCB3aGF0IHlvdSBzZWxlY3RlZC4KICAgICAgIAogMy4gUmVwZWF0IGEtYyBmb3IgdGhlIG5leHQgdmFyaWFibGUocyksIGUuZy4geW91IG1heSBuZWVkIGEgYm94IHRvIGluZGljYXRlIGB5ZWFyYCBpbiB0aGUgdGV4dCBib3ggYW5kIGB5ZWFyMWAgYW5kIGB5ZWFyMmAgaW4gdGhlIGRyb3AtZG93biBtZW51LiBEb24ndCBmb3JnZXQgdG8gdGljayB0aGUgdGljay1ib3ggZm9yIHRob3NlIHZhcmlhYmxlcyB0b28uCiAKIDQuICoqQ2xpY2sgb24gJ1RJRFknKioKIAogNS4gKipDbGljayBvbiAnR08gVE8gSEVBREVSUycqKgoKIVtdKFRpZHkuZ2lmKQoKIyMgSGVhZGVycyBhbmQgVW5pdHMgeyNIZWFkZXJzfQoKSGVyZSwgd2Ugd2FudCB0byBrbm93IGluIHdoYXQgY29sdW1uIHNvbWUga2V5IGluZm9ybWF0aW9uIGlzIHN0b3JlZC4KCiAxLiAqKklmLi4uKioKCiAgICAgLSAqKkEuIC4uLiB5b3VyIGRhdGEgZm9sbG93cyBvbmUgb2Ygb3VyIHByZS1sb2FkZWQgc3RhbmRhcmRzOioqIFlvdSBjYW4gc2VsZWN0IGl0IHRvIGhlbHAgZmlsaW5nIG91dCBzb21lIG9mIHRoZSBnZW5lcmFsIGluZm9ybWF0aW9uLiBCdXQgeW91IHNob3VsZCBkb3VibGUgY2hlY2sgdGhhdCBhY2N1cmF0ZWx5IGRlc2NyaWJlIHlvdXIgcGFydGljdWxhciBkYXRhIHNldC4KICAgICAtICoqQi4gLi4uIHlvdSBoYXZlIGFscmVhZHkgZ29uZSB0aHJvdWdoIHRoaXMgc3RlcCBhbmQgc2F2ZWQgeW91ciBwcm9maWxlICgucmRzIGZpbGUpOioqIFlvdSBjYW4gdXBsb2FkIHlvdXIgcHJvZmlsZS4gRG91YmxlIGNoZWNrIHRoYXQgdGhlIGluZm9ybWF0aW9uIGlzIGZpbGxlZCBvdXQgcHJvcGVybHkuCiAgICAgLSAqKkMuIC4uLlRoaXMgaXMgeW91ciBmaXJzdCB0aW1lIG9uIHRoaXMgcGFnZToqKiBZb3UgaGF2ZSB0byBnbyB0aHJvdWdoIGFsbCB0aGUgZHJvcC1kb3duIG1lbnVzOgogICAgICAgLSBjb2x1bW4gMTogR28gdGhyb3VnaCB0aGlzIGNvbHVtbiBiZWZvcmUgaW5kaWNhdGluZyBtb3JlIGluZm9ybWF0aW9uIGluIGNvbHVtbiAyLiBGb3IgZWFjaCBlbGVtZW50LCBzZWxlY3QgdGhlIG5hbWUgb2YgdGhlIGZpZWxkIG9mIHlvdXIgZGF0YSwgaWYgYW55LCB0aGF0IGNvcnJlc3BvbmRzIHRoZSBiZXN0IHRvIHdoYXQgaXMgYXNrZWQuIExlYXZlICJub25lIiBpZiBub25lIG9mIHlvdXIgdmFyaWFibGUgYXBwbHkuCiAgICAgICAtIGNvbHVtbiAyOiBDb21wbGV0ZSB0aGUgaW5mb3JtYXRpb24gb2YgdGhhdCBjb2x1bW4gYWZ0ZXIgeW91IGFyZSBkb25lIHdpdGggdGhlIGluZm9ybWF0aW9uIG9mIGNvbHVtbiAxLCBiZWNhdXNlIHNvbWUgZmllbGQgbWF5IGFwcGVhci9kaXNhcHBlYXIgZGVwZW5kaW5nIG9uIHdoYXQgeW91IGVudGVyZWQgaW4gMS4KICAgICAgIC0gT25jZSB5b3UgYXJlIGRvbmUsIHNhdmUgeW91ciBwcm9maWxlIChhIC5yZHMgZmlsZSkgc28geW91IHdvbid0IG5lZWQgdG8gZ28gdGhyb3VnaCBhbGwgb2YgdGhpcyBhZ2FpbiAoc2VlIEIuIGFib3ZlKSAKICAgICAgIAogMi4gKipjbGljayBvbiAnQVBQTFkgQ0hBTkdFUycqKiBhbmQgcmVhZCBhbnkgd2FybmluZ3MgdGhhdCBtYXkgcG9wdXAsIGFkanVzdCB5b3VyIGVudHJpZXMgaWYgcG9zc2libGUgKGl0IGlzIG9rYXkgdG8gaWdub3JlIHdhcm5pbmdzKSBhbmQgcmUtYXBwbHkgeW91ciBjaGFuZ2VzLiBTYXZlIChvciB1cGRhdGUgaWYgbmVlZGVkKSB5b3VyIHByb2ZpbGUgKC5yZHMgZmlsZSkKCiAzLiBDaGVjayB5b3VyIG5ldyBmb3JtYXRlZCBkYXRhIGxvb2tzIG9rLiBUaGUgaGVhZGVycyBhbmQgdW5pdHMgYXJlIG5vdyBmb2xsb3dpbmcgQVRGUydzIHN0YW5kYXJkLiBZb3UgY2FuIHNlZSB3aGF0IHRob3NlIGFyZSBieSBjbGlja2luZyB0aGUgbGl0dGxlIGByIGZhKG5hbWUgPSAiaW5mby1jaXJjbGUiKWAgYnV0dG9uLgogCiA1LiAqKmNsaWNrIG9uICdORVhUJyoqCgoKIVtdKEhlYWRlcnMuZ2lmKQoKIyMgQ29kZXMgeyNDb2Rlc30KCllvdSdsbCBiZSBwcm9tcHRlZCB0byB0aGlzIHRhYiBpZiB5b3UgaW5kaWNhdGVkIGNvbHVtbihzKSBmb3IgJ3RyZWUgY29kZXMnIGluIHRoZSBUcmVlIE1lYXN1cmVtZW50IHNlY3Rpb24gb2YgdGhlIHByZXZpb3VzIHRhYi4KClRoZSB0YWJsZSBzaG93cyB0aGUgbGlzdCBvZiBjb2RlcyB0aGF0IGFyZSBhdmFpbGFibGUgaW4gdGhlIGNvbHVtbihzKSB5b3UgaW5kaWNhdGVkLgpJZiB5b3UgaW50ZW5kIHRvIHRyYW5zbGF0ZSB0aGVzZSBjb2RlcyB0byBtYXRjaCB0aGUgb25lcyBvZiBhbm90aGVyIHByb2ZpbGUgKHdoaWNoIHlvdSB3aWxsIGJlIGFibGUgdG8gZG8gYXQgYSBsYXRlciBzdGVwKSwgb3IgdmljZSB2ZXJzYSwgeW91IG5lZWQgdG8gZmlsbCB0aGlzIHRhYmxlIG91dC4KCk9uY2UgeW91IGFyZSBkb25lIHdpdGggdGhlIHRhYmxlIHlvdSBjYW4gdXBkYXRlIHlvdXIgcHJvZmlsZSAoYnkgZG93bmxvYWRpbmcgYW5kIG92ZXJ3cml0aW5nIHlvdXIgLnJkcyBmaWxlKSwgc28gaXQgd2lsbCBiZSBmYXN0ZXIgbmV4dCB0aW1lLiBJZiB5b3UgaGF2ZSBhbHJlYWR5IHNhdmVkIHlvdXIgcHJvZmlsZSBhZnRlciB0aGlzIHN0ZXAsIGFuZCB1c2VkIGl0IHRvIGZpbGwgb3V0IHRoZSBwcmV2aW91cyBzdGVwLCB5b3UgY2FuIGNsaWNrIG9uIHRoZSAiVXNlIHlvdXIgcHJvZmlsZSIgYnV0dG9uIHRvIGF1dG9tYXRpY2FsbHkgZmlsbCB0aGUgdGFibGUuCgoKVGhlcmUgaXMgYSBsaXN0IG9mIHByZWRlZmluZWQgZGVmaW5pdGlvbnMsIHdoaWNoLCBpZiB1c2VkIGJ5IHlvdSBhbmQgeW91ciBjb2xsYWJvcmF0b3IsIHdpbGwgaGVscCBhdXRvbWF0aWNhbGx5IHRyYW5zbGF0ZSB5b3VyIGNvZGVzLiBCdXQgaWYgeW91IGNhbid0IGZpbmQgYSBkZWZpbml0aW9uIHRoYXQgbWF0Y2hlcyB5b3VycywganVzdCB0eXBlIHlvdXIgb3duLgoKCiFbXShDb2Rlcy5naWYpCgojIyBDb3JyZWN0aW9ucyB7I0NvcnJlY3R9CgpDb3JyZWN0aW9ucyBtYXkgYmUgYXBwbGllZCB0byBib3RhbmljYWwgbmFtZXMsIGxpZmUgc3RhdHVzIGFuZC9vciBkaWFtZXRlcnMuCgpJZiB5b3UgYXJlIHBsYW5pbmcgb24gdXNpbmcgY29ycmVjdGlvbnMsIHdlIHJlY29tbWVuZCB0aGF0IHlvdSBjb29yZGluYXRlIHdpdGggeW91ciBjb2xsYWJvcmF0b3IocyksIGJlY2F1c2UgaXQgbWF5IG1ha2UgbW9yZSBzZW5zZSB0byBmaXJzdCBza2lwIHRoZW0gYW5kIGFwcGx5IHRoZW0gaW4gYSBuZXcgYXBwIHNlc3Npb24gaW4gd2hpY2ggdGhlIGNvbGxhdGVkIGRhdGEgc2V0IGlzIHVwbG9hZGVkLCB0byBlbnN1cmUgdW5pZm9ybWl0eSBvZiBjb3JyZWN0aW9ucyBhY3Jvc3MgZGF0YSBzZXRzLgoKCklmIHlvdSBzZWxlY3QgIlllcyIgdG8gYW55IG9mIHRoZSBjb3JyZWN0aW9ucywgeW91IHdpbGwgYmUgYWJsZSB0byBjaGFuZ2UgdGhlIGRlZmF1bHQgcGFyYW1ldGVycy4gV2UgcmVjb21tZW5kIHRvIGtlZXAgbW9zdCBwYXJhbWV0ZXJzIHRvIHRoZWlyIGRlZmF1bHQgdmFsdWVzLgoKVGhlIGZ1bmN0aW9ucyB3aWxsIGFkZCBuZXcgY29sdW1ucyB0byB5b3VyIGRhdGEgKGluZGljYXRlZCB3aXRoIGBfRGF0YUhhcm1vbml6YXRpb25Db3JgIHN1ZmZpeCkgYW5kIHdvbid0IGFsdGVyIHlvdXIgb3JpZ2luYWwgY29sdW1ucy4KCk5vdGUgdGhhdCBzb21lIG9mIHRoZXNlIGZ1bmN0aW9uIGFyZSBxdWl0ZSBzbG93IGFuZCBpdCBjYW4gdGFrZSBhIGZldyBtaW51dGVzIGZvciB0aGUgb3V0cHV0IHRvIHNob3cgdXAuCgpZb3UgY2FuIHZpc3VhbGl6ZSB0aGUgY29ycmVjdGlvbiBhcHBsaWVkIGluIHRoZSB0YWJzIGJlbG93IHRoZSBjb3JyZWN0aW9uIGJveGVzLgoKCgohW10oQ29ycmVjdGlvbnMuZ2lmKQoKIyMgT3V0cHV0IGZvcm1hdCB7I091dHB1dEZvcm1hdH0KCiMjIyBTZWxlY3RpbmcgYW4gb3V0cHV0IGZvcm1hdAoKVGhpcyBpcyB3aGVyZSB0aGUgbWFnaWMgaGFwcGVucy4KClNlbGVjdCBvciB1cGxvYWRlZCBhbiBvdXRwdXQgcHJvZmlsZSAoLnJkcyBmaWxlKSBhbmQgY2xpY2sgb24gKipBcHBseSBQcm9maWxlKiouIFRoaXMgd2lsbCB0cmFuc2Zvcm0geW91ciBkYXRhJ3MgdW5pdHMgYW5kIGNvbHVtbiBuYW1lcyBpbnRvIHRoZSBvdXRwdXQgcHJvZmlsZSdzIGhlYWRlcnMgYW5kIHVuaXRzLiBJZiB5b3UgYW5kIHlvdXIgY29sbGFib3JhdG9yIGhhdmUgYSBjb2RlIHRhYmxlLCB5b3Ugd2lsbCBiZSBwcm9tcHRlZCB0byB0aGUgW2NvZGUgdHJhbnNsYXRpb24gdGFibGVdKCNUcmFuc2xhdGluZ0NvZGUpLiBJZiBub3QsIHlvdSBjYW4gY2hlY2sgdGhhdCB0aGUgb3V0cHV0IGRhdGEgbG9va3MgZ29vZCBhbmQgbW92ZSBvbiB0byBbJ3RoZSBkb3dubG9hZCB0YWInXSgjU2F2ZSkuCgpOb3RlOiBXaGVuIHlvdSB1cGxvYWQgYSBwcm9maWxlLCB0aGVyZSBpcyBhIGNoYW5jZSB0aGF0IGl0IGlzICJvYnNvbGV0ZSIgaWYgdGhlIHByb2ZpbGUgd2FzIGNyZWF0ZWQgb24gYW4gZWFybGllciB2ZXJzaW9uIG9mIHRoZSBhcHAuIElmIHRoYXQgaXMgdGhlIGNhc2UsIHlvdSdsbCBiZSBub3RpZmllZCBieSBhIHBvcCB1cCB3aW5kb3cgYW5kIHRoZSBpdGVtcyBtaXNzaW5nIGluIHRoZSBwcm9maWxlIHdpbGwgYmUgbGlzdGVkLiBUbyBiZSBhYmxlIHRvIHVzZSB0aGF0IHByb2ZpbGUsIHlvdSB3aWxsIG5lZWQgYW4gdXBkYXRlZCB2ZXJzaW9uIG9mIGl0IChzZWUgW2BIb3cgdG8gdXBkYXRlIGEgcHJvZmlsZWBdKCN1cGRhdGVQcm9maWxlKSBpbiB0aGUgW2BUcm91Ymxlc2hvb3RpbmdgXSgjVHJvdWJsZXNob290aW5nKSBzZWN0aW9uIGJlbG93LikgCgoKIyMjIFRyYW5zbGF0aW5nIGNvZGUgeyNUcmFuc2xhdGluZ0NvZGV9CgpUaGlzIHNlY3Rpb24gb2YgdGhlIHRhYiB3aWxsIG9ubHkgYXBwZWFyIGlmIHlvdSBoYWQgdG8gZmlsbCBpbiB0aGUgY29kZSB0YWJsZSBpbiB0aGUgW2BDb2RlcyB0YWJgXSgjQ29kZXMpIGFuZCB0aGUgb3V0cHV0IHByb2ZpbGUgeW91IHNlbGVjdGVkIG9yIHVwbG9hZGVkIGFsc28gaGFzIGEgY29kZSB0YWJsZS4gWW91IGNhbiBub3cgbG9vayB0aHJvdWdoIGJvdGggc2V0cyBvZiBjb2RlcyBhbmQgaW5kaWNhdGUgdGhlIG9uZXMgdGhhdCBhcmUgZXF1aXZhbGVudCBieSBjaGVja2luZyB0aGUgY29ycmVzcG9uZGluZyByYWRpbyBidXR0b24ocykuCgpJZiB5b3UgaG92ZXIgb3ZlciB0aGUgY29sdW1uIG5hbWVzLCB5b3Ugd2lsbCBzZWUgdGhlIGRlZmluaXRpb25zIG9mIHRoZSBvdXRwdXQgcHJvZmlsZS4KCkNsaWNrIG9uICJTZWUgZGVmaW5pdGlvbiIgdG8gZG91YmxlIGNoZWNrIHRoYXQgdGhlIG1hcHBpbmcgb2YgY29kZXMgaXMgd2hhdCB5b3UgaW50ZW5kZWQuIAoKV2hlbiB5b3UgYXJlIGhhcHB5LCBhcHBseSB0aGUgbWFwcGluZyBhbmQgeW91IHdpbGwgc2VlIGNvbHVtbnMgYWRkZWQgdG8geW91ciB0YWJsZS4gVGhleSB3aWxsIGhhdmUgdGhlIGNvbHVtbiBuYW1lcyB0aGF0IHRoZSBvdXRwdXQgcHJvZmlsZSBleHBlY3RzIGFuZCB3aWxsIGJlIGZpbGxlZCB3aXRoIHRoZSBvdXRwdXQgY29kZXMsIGJhc2VkIG9uIHRoZSBjb2RlcyBpbiB5b3VyIGNvbHVtbihzKSBhbmQgdGhlIG1hcHBpbmcgeW91IGluZGljYXRlZC4KCgohW10oQ29kZV90cmFuc2xhdGlvbi5naWYpCgojIyBEb3dubG9hZCB0aGUgb3V0cHV0IGRhdGEgYW5kIG1ldGFkYXRhIHsjU2F2ZX0KCkNsaWNraW5nIG9uICJzYXZlIGFsbCIgZ2VuZXJhdGVzIGEgemlwIGZpbGUgd2l0aCBhbGwgdGhlIGZpbGVzIHlvdSBzaG91bGQgbmVlZC4gCklmIHlvdSBoYXZlIHRyZWUgY29kZXMgYW5kIGFwcGxpZWQgYSB0cmVlIGNvZGUgbWFwcGluZywgdGhlIHppcCB3aWxsIGluY2x1ZGUgYSBDU1YgZmlsZSB3aXRoIHRoZSB0cmFuc2xhdGlvbiB0YWJsZSAod2hpY2ggeW91IGNhbiB1cGxvYWQgaW4gdGhlIGNvZGUgdHJhbnNsYXRpb24gc3RlcCB0byBzcGVlZCB1cCB0aGUgcHJvY2VzcyBuZXh0IHRpbWUuKQoKCiFbXShEb3dubG9hZC5naWYpCgojIyBIZWxwIHsjSGVscH0KClRoaXMgYSBzaW1wbGlmaWVkIHZlcnNpb24gb2YgdGhpcyB0dXRvcmlhbC4KCiMgVHJvdWJsZXNob290aW5nIHsjVHJvdWJsZXNob290aW5nfQoKIyMgSG93IHRvIHVwZGF0ZSBhIHByb2ZpbGUgeyN1cGRhdGVQcm9maWxlfQoKSWYgeW91ciBvdXRwdXQgcHJvZmlsZSAoLnJkcyBmaWxlKSBpcyBvYnNvbGV0ZSB0aGVyZSBhcmUgdHdvIG9wdGlvbnMsIHdoaWNoIHNob3VsZCBiZSBkb25lIGJ5IHRoZSBwZXJzb24gd2hvIGNyZWF0ZWQgdGhlIHByb2ZpbGUgaW4gdGhlIGZpcnN0IHBsYWNlOgoKLSBGb3IgUiBzYXZ2eSBwZW9wbGU6IG9wZW4gdGhlIC5yZHMgZmlsZSBpbiBSLiBJdCBpcyBhIGBsaXN0YC4gQWRkIHRoZSBtaXNzaW5nIGVsZW1lbnQocykgdGhhdCB3ZXJlIGxpc3RlZCBpbiB0aGUgcG9wIHVwIHdpbmRvdyB0aGF0IHNhaWQgdGhhdCB0aGUgcHJvZmlsZSB3YXMgb2Jzb2xldGUgYnkgZ2l2aW5nIHRoZW0gdGhlIHZhbHVlIHRoYXQgYXBwbGllcyB0byB0aGUgb3V0cHV0IHByb2ZpbGUuCkZvciBleGFtcGxlLCBpZiAiQ2x1c3RlciIgd2FzIG1pc3NpbmcgeW91IGNhbiBkbzoKCiAgICAgICAgcHJvZmlsZSA8LSByZWFkUkRTKCJbWU9VUiBQQVRIXS9bWU9VUiBQUk9GSUxFTkFNRV0ucmRzIikKICAgICAgICBwcm9maWxlJENsdXN0ZXIgPC0gIm5vbmUiCiAgICAgICAgc2F2ZVJEUyhwcm9maWxlLCAiW1lPVVIgUEFUSF0vW1lPVVIgUFJPRklMRU5BTUVdLnJkcyIpCgoKLSBGb3Igbm9uLVIgc2F2dnkgcGVvcGxlOiBnbyB0aHJvdWdoIHRoZSBhcHAgYWdhaW4uIEl0IHNob3VsZCBnbyBmYXN0IGFzIHlvdSB3aWxsIGJlIGFibGUgdG8gdXBsb2FkIHlvdXIgb2Jzb2xldGUgcHJvZmlsZSBhcyBhbiBpbnB1dC4gTWFrZSBzdXJlIHRvIHNhdmUgYW5kIG92ZXJ3cml0ZSB5b3VyIHByb2ZpbGUuIElmIHRoZSBlbGVtZW50cyBtaXNzaW5nIGRpZCBub3QgYXBwbHkgdG8geW91LCB0aGV5IHdpbGwgbm93IGV4aXN0IHdpdGggdmFsdWUgIm5vbmUiIGluIHlvdXIgcHJvZmlsZS4KCg==